package beastick.security.generic;

//Copyright 2008 Tofig Kareemov, estereos@gmail.com
//
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//
//http://www.apache.org/licenses/LICENSE-2.0
//
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.

/**
 * 
 * This class contains methods for Secure GUID generation. Class could be used
 * as instanciated(one per GUID) or static(one per system) object
 * 
 * String GUID = (new SecureGUID()).toString(); or SecureGUID oGUID = (new
 * SecureGUID()); GUID[1] = oGUID.Rehash()toString(); GUID[2] =
 * oGUID.Rehash()toString(); GUID[3] = oGUID.Rehash()toString();
 * 
 * @author tofig
 */
public final class SecureGUID
{
  private static final beastick.security.generic.SecureRandom oSecureRandomGUID       = new beastick.security.generic.SecureRandom(
                                                                                           16);
  private static final int[]                                     I_STRING_PORTION_LENGTH = new int[]
                                                                                         {
    4, 2, 2, 2, 6
                                                                                         };
  private static final int                                       I_FIRST_LETTER          = (byte) 'A';
  private static final char[]                                    S_HEX_CHAR              = new char[]
                                                                                         {
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
    'F'
                                                                                         };

  public SecureGUID()
  {
  }

  public SecureGUID(Object oInput)
  {
    SetGUIDSeed(oInput);
  }

  /**
   * This methods sets a new value to the Secure GUID generation seed.
   * 
   * @param oInput
   *          String, byte[], int[] or short[]
   */
  public final void SetGUIDSeed(Object oInput)
  {
    synchronized (oSecureRandomGUID)
    {
      oSecureRandomGUID.SetSeed(oInput);
    }
  }

  /**
   * This method generates the next random GUID.
   *  
   */
  public final SecureGUID Rehash()
  {
    synchronized (oSecureRandomGUID)
    {
      oSecureRandomGUID.RehashSeed();
    }
    return this;
  };

  /**
   * This method returns the String that represents the Random GUID in ABC
   * format. ABC format is a hexadecimal representation of the number were only
   * latin letters are used (no digits). A = 0, B = 1, ... This format usually
   * used to improve the performance of the system were many GUIDs required in
   * short period of time
   * 
   * @return String
   * @see toString()
   */
  public final String toStringABC()
  {
    char[] sResult = new char[32];
    int i = 0;
    int i3 = 0;
    int[] iGUIDSeed = null;
    synchronized (oSecureRandomGUID)
    {
      iGUIDSeed = oSecureRandomGUID.GetSeed();
    }
    for (i = 0; i < 16; ++i)
    {
      sResult[i3++] = (char) (I_FIRST_LETTER + (iGUIDSeed[i] & 0x0F));
      sResult[i3++] = (char) (I_FIRST_LETTER + ((iGUIDSeed[i] >> 4) & 0x0F));
    }
    return String.valueOf(sResult);
  }

  /**
   * This method returns the String that represents the Random GUID in a
   * standard way
   * 
   * @see java.lang.Object#toString()
   */
  public final String toString()
  {
    char[] sResult = new char[36];
    int i = 0;
    int i1 = 0;
    int i2 = 0;
    int i3 = 0;
    int[] iGUIDSeed = null;
    synchronized (oSecureRandomGUID)
    {
      iGUIDSeed = oSecureRandomGUID.GetSeed();
    }
    i1 = 0;
    for (i2 = 0; i2 < 5; ++i2)
    {
      if (i2 > 0)
      {
        sResult[i3++] = '-';
      }
      for (i = 0; i < I_STRING_PORTION_LENGTH[i2]; ++i)
      {
        sResult[i3++] = S_HEX_CHAR[iGUIDSeed[i1] & 0x0F];
        sResult[i3++] = S_HEX_CHAR[(iGUIDSeed[i1] & 0xF0) >> 4];
        ++i1;
      }
    }
    return String.valueOf(sResult);
  }
}